前言
Webpack 作为普遍使用的打包工具,在开发和发布的过程中产出的代码结构,你是否关心过?本文为你揭开它的神秘面纱。
1、开发模式
一般情况,开发的过程都会使用 devServer 并开启 hot 热更新。假如我们有一个页面入口文件 index.js 和依赖模块 dateUtils.js,代码如下:
|
|
Ok,我们来看打包后的代码:
|
|
打包后的代码在浏览器中格式化之后非常多,对于我们来说,我们的关注放在代码块和打包后的代码执行流程上,精简一下:
|
|
我们看到打包后的代码其实就是一个 IIFE。这个函数接受一个对象类型的参数,其中这个参数的 key 就是模块路径,value 则是对模块代码包裹后的一个函数,该函数有几个固定参数(这个其实可以解释 Node 中模块文件中 require 和 module 是如何来的?其实就是 Node 在模块之外包装了一层,把 require 和 module 给传了进来)。暂且先不管参数具体是什么,我们接着看函数体里是什么:
|
|
我们看函数体里定义了很多对象和方法,含有 hot 的部分基本上和热更新模块相关。这些是被添加进来的代码,最终上线是没有的。我们直接看函数体的最后一行,它执行了 hotCreateRequire(0)(webpack_require.s = 0)。这一行两个括号,很明显 hotCreateRequire 是返回了一个函数出来。我们接下来看看看 hotCreateRequire :
|
|
启动的时候,传入了 moduleId 是 0,在 installedModules 中找不到模块,直接返回了 webpack_require。然后继续执行这个返回的函数,并传入参数 webpack_require.s = 0,那么其实是执行了下面这个函数代码:
|
|
这个函数,通过 webpack_require 执行了三个模块,前两个是在 devServer 添加的入口文件,为了实现开发和热更新的一些功能。最后一行 moduel.exports 属性是我们的 index.js 模块执行的返回,这样就执行到了我们的程序入口。
在 index.js 中我们看到通过 import 导入的 dateutils 也是通过 webpack_require 进行模块引用的,并对里面的方法进行了调用。那么,以此类推,所有的模块引用都是这么实现的。
2、生产模式
我们把这个代码使用生产模式进行打包,可以得到如下代码:
|
|
因为,我们的代码足够简单,没有其他的依赖模块被打进来。和开发模式类似,整体上它也是一个 IIFE,只不过做了一些混淆和压缩的处理。另外,参数变成了数组类型。同时,去掉了开发模式下的一些辅助代码。我们很容易和上面的东西做一些对应(见注释)。
3、再进一步
OK,开发模式和生产模式的代码结构几乎一样。只是参数类型略有差别,开发模式下,key 是作为模块的标识来使用的。热更新开启后,修改模块可以很轻易的修改该模块的代码。
另外,我们的项目代码里无论是使用 require/module.exports 这种 ComomonJS 的模块化方案,还是采用 import/export 的 ESM 模块化方案。通过 webpack 打包最终其实是 ComomonJS 的模块化方案,也就是说,它可以像 CommonJs 那样进行动态模块引用。
还有就是如果使用了 ESM 的 export (仅有 export.default 这种方式除外,它和 CommonJS 没什么差别,都是只导出了一个对象出来),在打包后的代码有一些区别。比如:
|
|
这里出来了 .d 和 .r 方法,这个在函数里有定义:
|
|
Ok,通过定义 getter 函数的方式,我们在 esmtest.js 中对于 flag 的改动代码起了作用,随后在 2s 后的定时器中的打印也说明了这一点。
最后一个是如果采用代码分割或动态引入的情况下,会怎么样?我们直接上打包前的代码:
|
|
我们再来看在开发模式下打包的代码在浏览器里多了一个 chunk 文件请求,里面打包后的代码如下:
|
|
主体代码没什么差别,就是我们的 dynamicImport.js 模块的代码,然后外面调用了 window[“webpackJsonp”].push 这个方法。那么这个方法是哪里来的,我们看一下 index.js 打包后的代码部分:
|
|
我们简单看一下上面的这部分代码。首先,这部分代码先执行,在 window 上挂载了一个 window[“webpackJsonp”],并为它定义了一个 push 方法就是 webpackJsonpCallback,用于从异步请求的文件中加载模块。此外,定义一个 webpack_require.e 方法去异步请求 chunk 文件,并返回一个 Promise 对象。
至此,关于 Webpack 打包后的内容部分的介绍全部结束,你学废了吗?